#include "sdk.h"
#include "headerguard.h"
#include "M_Code_StyledTextCtrl.h"

namespace {
  PluginRegistrant<HeaderGuard> reg( _T( "HeaderGuard" ) );
}

void HeaderGuard::OnAttach() {
  Manager::Get()->RegisterEventSink( cbEVT_EDITOR_BEFORE_SAVE, new cbEventFunctor<HeaderGuard, CodeBlocksEvent>( this, &HeaderGuard::OnSave ) );
}

void HeaderGuard::OnSave( CodeBlocksEvent& event ) {
  M_Code_Editor* ed = ( M_Code_Editor* ) event.GetEditor();
  wxString n = ed->GetFilename();
  if( !n.Right( 2 ).Lower().IsSameAs( _T( ".h" ) ) && !n.Right( 3 ).Lower().IsSameAs( _T( ".hpp" ) ) && !n.Right( 3 ).Lower().IsSameAs( _T( ".hxx" ) ) ) {
    return;
  }
  const wxString s( ed->GetControl()->GetLine( 0 ).Trim( true ).Trim( false ) );
  if( s.StartsWith( _T( "#ifndef" ) ) && ( s.Contains( _T( "HEADER" ) ) || s.Right( 2 ).IsSameAs( _T( "_H" ) )
      || s.Contains( _T( " H_" ) ) || s.Contains( _T( "_H_" ) ) || s.Contains( _T( "_INCLUDED" ) ) ) ) {
    return;
  }
  unsigned int s1 = 257, s2 = 123, b = 9737333, c = 174440041;
  for( unsigned int i = 0; i < n.length(); ++i ) {
    b = ( b * 33 ) + ( s1 += n[i] );
    ( c *= 47 ) += s2;
    s2 += s1;
  }
  b ^= ( ( ( s1 % 255 ) << 10 ) | ( s2 & 255 ) );
  c ^= ( c << 14 );
  b ^= ( b << 21 );
  c ^= ( c >> 5 );
  b ^= ( b >> 17 );
  c ^= ( c << 11 );
  b ^= ( b << 9 );
  n.Printf( _T( "#ifndef HEADER_%X%X\n#define HEADER_%X%X\n\n" ), b, c, b, c );
  ed->GetControl()->BeginUndoAction();
  ed->GetControl()->InsertText( 0, n );
  ed->GetControl()->InsertText( ed->GetControl()->GetLength() - 1, _T( "\n#endif  // header guard \n" ) );
  ed->GetControl()->EndUndoAction();
}
